package com.summer.common.lib.context.impl;

import com.summer.common.lib.context.Initialize;
import com.summer.common.lib.context.InitializeStep;
import com.summer.common.lib.context.Instantiate;
import com.summer.common.lib.config.Load;
import com.summer.common.lib.config.WebConfig;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Modifier;
import java.util.stream.Stream;

public class JNDIInitialize implements Initialize, InitializeStep {

    private Instantiate instantiate;

    public JNDIInitialize(Instantiate instantiate) {
        this.instantiate = instantiate;
        this.initializeComponents();
    }

    @Override
    public void initializeComponents() {
        this.instantiate.getAllComponents().values().forEach(component -> {
            Class<?> componentClass = component.getClass();
            // 注入阶段 - {@link Resource}
            inject(component, componentClass);
            // 初始阶段 - {@link PostConstruct}
            processPostConstruct(component, componentClass);
            // TODO 实现销毁阶段 - {@link PreDestroy}
            processPreDestroy(component, componentClass);
        });
    }

    @Override
    public void inject(Object component, Class<?> componentClass) {
        Stream.of(componentClass.getDeclaredFields())
                .filter(field -> {
                    int mods = field.getModifiers();
                    return !Modifier.isStatic(mods) &&
                            field.isAnnotationPresent(Resource.class) ||
                            field.isAnnotationPresent(Load.class)
                            ;
                }).forEach(field -> {
            Object injectedObject = null;
            if (field.isAnnotationPresent(Resource.class)) {
                Resource resource = field.getAnnotation(Resource.class);
                String resourceName = resource.name();
                injectedObject = this.instantiate.lookupComponent(resourceName);
            } else if (field.isAnnotationPresent(Load.class)) {
                Load load = field.getAnnotation(Load.class);
                String propName = load.name();
                injectedObject = WebConfig.keyParser(propName);
            }
            try {
                field.setAccessible(true);
                // 注入目标对象
                field.set(component, injectedObject);
            } catch (IllegalAccessException e) {
                System.out.println(e);
            }
        });
    }

    @Override
    public void processPostConstruct(Object component, Class<?> componentClass) {
        Stream.of(componentClass.getMethods())
                .filter(method ->
                        !Modifier.isStatic(method.getModifiers()) &&      // 非 static
                                method.getParameterCount() == 0 &&        // 没有参数
                                method.isAnnotationPresent(PostConstruct.class) // 标注 @PostConstruct
                ).forEach(method -> {
            // 执行目标方法
            try {
                method.invoke(component);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    @Override
    public void processPreDestroy(Object component, Class<?> clazz) {

    }
}
